home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / challenge / 12.04-Apr96 / LifeTestCode DR3.sit / Life TestCode DR3 / Chal9604TC.c < prev    next >
C/C++ Source or Header  |  1996-04-03  |  38KB  |  1,555 lines

  1. /*    MacTech Challenge April 1996
  2.     MutantLife Test Code
  3.     ©Ludovic Nicolle 1996
  4.     
  5.     Link your solution in PropagateLife.c
  6.     
  7.     
  8.     and include Chal9604TC.rsrc in the project.
  9.  
  10.     Data files available to test with can be obtained from the
  11.     challenge ftp site, and on a limited basis from the Challenge-D
  12.     Mailing List
  13.  
  14. /*
  15. constants
  16. */
  17. #define kAppleMenu    128
  18. #define kFileMenu        129
  19. #define kLifeMenu        131
  20. #define kTestMenu        132
  21.  
  22. #define kNew        1
  23. #define kOpen        2
  24. #define kClose        3
  25. #define kSave        5
  26. #define kSaveAs    6
  27. #define kAppend    7
  28. #define kQuit        12
  29.  
  30. #define kChangeSettings        1
  31. #define kPropagate            3
  32. #define kPropagateOneStep    4
  33. #define kReturnToInitial    6
  34. #define kStartFromCurrent    7
  35.  
  36. #define kTestWhole            1
  37. #define kTestContinue        2
  38. #define kDisplayInitial        4
  39. #define kDisplayPrevious    5
  40. #define kDisplayCurrent        6
  41. #define kDisplayGood            8
  42. #define kDisplayErrors        9
  43.  
  44. /* custom compiler flags*/
  45.  
  46.  
  47. /*profiling under CodeWarrior */
  48. #ifdef __MWERKS__
  49. //#define _profile_    /*Uncomment this if you want to profile under CW    */
  50. #include "profiler.h"
  51. #endif
  52.  
  53. #include "stdio.h"
  54. /* Solutions header    */
  55. #include "PropagateLife.h"
  56.  
  57. /* Bitmap Initialization function    */
  58. #include "LifeScramble.h"
  59. /* File format, Saving and Opening    */
  60. #include "LifeFile.h"
  61. /*    Graphic Display of the Bitmaps in a window    */
  62. #include "LifeWindow.h"
  63.  
  64. short    gQuit =  false;
  65.  
  66. /* timing utils. See example of use in PropagateCurrent()*/
  67. #include <Timer.h>
  68. UnsignedWide    mbefore,
  69.                     mafter;
  70. long                mdiff = 0;
  71.  
  72. /*If you link some bitmap initialization routine or use the default one
  73.     and want it to be used on any new BitMap before manual setting, let this
  74.     value to 1. If you want to bypass automatic Initialization, set it to 0*/
  75. #define    _UseInitCells_        0
  76.  
  77.  
  78. /* Various Globals. File, Window, Bitmap etc.    */
  79. /* Don't change these without reflexion!    */
  80. WindowPtr    gLifeW = nil;
  81. short            gLifeFile = 0;
  82. FSSpec        gLifeSpec;
  83. Boolean        gInitialSaved =  false,
  84.                 gCurrentSaved;
  85. GrafPort        gInitialState,    /* allocate these four GrafPort statically*/
  86.                 gPreviousState,
  87.                 gCurrentState,
  88.                 gTempFinalState,
  89.                 gErrorState;
  90.  
  91. short            gDisplayState = 0;
  92.  
  93. Rect            gDisplayRect;
  94. Rect            defaultRect;
  95.  
  96. Boolean        gInTest = false;
  97.  
  98. LifeRun        gLifeRun;
  99. long            gCurGen = 0;    /* current generation of current run. 0 = start    */
  100. Boolean        gRecord = true;
  101. Boolean        gIntermediate = false;
  102.  
  103. short            gInterStep = 1;
  104. unsigned char    gMessage1[256],
  105.                     gMessage2[256];
  106. /* End of don't-touch-if-you-don't-understand-gloabals */
  107.  
  108. /*    DEFAULT APPEARANCE SETTINGS    */
  109. /*            these controls are not critical and only change display    
  110.             so change them and see            */
  111. Point            gMessageZone = {50, 5};
  112. Boolean        gToroidLike = true;
  113. short            gToroidLimit =  3;    /*under that size, dont draw grid and mirror*/
  114. Boolean        gDrawGrid = true;
  115.  
  116.  
  117.  
  118. /*    DEFAULT LIFE SETTINGS            */
  119. /*                these ones are available under the Chnage Settings Dialog.
  120.                 you can chnage the default values here since     */
  121. long            gMaxGens = 10;        
  122. Point            gLifeSize = {20, 20};
  123. short            gBirth = 0x0008, /*    Default  birth and death rules    */
  124.                 gDeath = 0x01F3;
  125.  
  126.  
  127.  
  128.  
  129.  
  130. void InitAll(void);
  131. void ChangeSettings(void);
  132. void OpenFile(void);
  133. void CloseFile(void);
  134. void DoSave(void);
  135. void AppendtoFile(void);
  136.  
  137. void NewRun(void);
  138. void PropagateCurrent();
  139. void PropagateCurrentbyOne();
  140. void ReturnToInitial(void);
  141. void StartFromCurrent(void);
  142.  
  143. void TestWholeFile(void);
  144. void TestFileStep(void);
  145. void UpdateLifeWindow(void);
  146. void DoNothing();
  147.  
  148. void DoAboutBox(void);
  149. void main(void);
  150.  
  151. void PrepareMenus(void);
  152. void DoMenu(long menusel);
  153. void DoKey(EventRecord *event);
  154. void DoMouseDown(EventRecord *event);
  155.  
  156. void InitAll(void)
  157. {
  158.     Handle    mbarHdl;
  159.         
  160.     InitGraf(&qd.thePort);
  161.     InitFonts();
  162.     InitWindows();
  163.     InitMenus();
  164.     TEInit();
  165.     InitDialogs(nil);
  166.     InitCursor();
  167. //Get the Menu Bar
  168.     mbarHdl = GetNewMBar(128);
  169.     SetMenuBar(mbarHdl);
  170.     DisposeHandle(mbarHdl);
  171.     DrawMenuBar();
  172.     AppendResMenu(GetMenuHandle(kAppleMenu), 'DRVR');
  173.     OpenPort(&gInitialState);
  174.     OpenPort(&gPreviousState);
  175.     OpenPort(&gCurrentState);
  176.     OpenPort(&gTempFinalState);
  177.     OpenPort(&gErrorState);
  178.     
  179.     gInitialState.portBits.baseAddr = nil;
  180.     gPreviousState.portBits.baseAddr = nil;
  181.     gCurrentState.portBits.baseAddr = nil;
  182.     gTempFinalState.portBits.baseAddr = nil;
  183.     gErrorState.portBits.baseAddr = nil;
  184.  
  185. {GDHandle gd;
  186. short mBarHeight;
  187.   mBarHeight = LMGetMBarHeight();
  188.   gd = GetMainDevice();
  189.   defaultRect = (**gd).gdRect;
  190.   defaultRect.top = mBarHeight+20;
  191.   defaultRect.left = 10;
  192.   defaultRect.right -= 10;
  193.   defaultRect.bottom -= 10;
  194. }
  195. }
  196.  
  197. void ChangeSettings(void)
  198. {
  199.     GrafPtr        savePort;
  200.     DialogPtr    myDialog;
  201.     short            itemHit = 0;
  202.     Str255        theString;
  203.     long            stringvalue;
  204.     short            iType;
  205.     Handle        iHandle;
  206.     Rect            iRect;
  207.     Point            previousSize = gLifeSize;
  208.     short            prevBirth = gBirth,
  209.                     prevDeath = gDeath;
  210.     long            prevMax = gMaxGens;
  211.     
  212.     myDialog = GetNewDialog(128, nil, (WindowPtr)-1);
  213.     if (myDialog == nil)
  214.         return;
  215.     GetPort(&savePort);
  216.     SetPort(myDialog);
  217.     SetDialogDefaultItem(myDialog, 1);
  218.     SetDialogCancelItem(myDialog, 2);
  219.  
  220.     GetDialogItem(myDialog, 3, &iType, &iHandle, &iRect);
  221.     NumToString(gMaxGens, theString);
  222.     SetDialogItemText(iHandle, theString);
  223.     
  224.     GetDialogItem(myDialog, 4, &iType, &iHandle, &iRect);
  225.     NumToString(gLifeSize.h, theString);
  226.     SetDialogItemText(iHandle, theString);
  227.     
  228.     GetDialogItem(myDialog, 5, &iType, &iHandle, &iRect);
  229.     NumToString(gLifeSize.v, theString);
  230.     SetDialogItemText(iHandle, theString);
  231.  
  232.     GetDialogItem(myDialog, 39, &iType, &iHandle, &iRect);
  233.     NumToString(gInterStep, theString);
  234.     SetDialogItemText(iHandle, theString);
  235.  
  236.     GetDialogItem(myDialog, 9, &iType, &iHandle, &iRect);
  237.     SetControlValue((ControlHandle)iHandle, gRecord);
  238.  
  239.     GetDialogItem(myDialog, 10, &iType, &iHandle, &iRect);
  240.     SetControlValue((ControlHandle)iHandle, gIntermediate);
  241.  
  242.     for (itemHit = 0; itemHit <= 8; itemHit++)
  243.     {
  244.         GetDialogItem(myDialog, 11 + itemHit * 2, &iType, &iHandle, &iRect);
  245.         SetControlValue((ControlHandle)iHandle, (gBirth >> itemHit) & 0x01);
  246.     }
  247.  
  248.     for (itemHit = 0; itemHit <= 8; itemHit++)
  249.     {
  250.         GetDialogItem(myDialog, 12 + itemHit * 2, &iType, &iHandle, &iRect);
  251.         SetControlValue((ControlHandle)iHandle, (gDeath >> itemHit) & 0x01);
  252.     }
  253.     
  254.     ShowWindow(myDialog);    
  255.     while ((itemHit != 1) && (itemHit != 2))
  256.     {
  257.         ModalDialog(nil, &itemHit);
  258.         if ((itemHit >= 9) && (itemHit <= 28))    /*checkbox inversion*/
  259.         {
  260.             GetDialogItem(myDialog, itemHit, &iType, &iHandle, &iRect);
  261.             iType = GetControlValue((ControlHandle)iHandle);
  262.             SetControlValue((ControlHandle)iHandle, !iType);
  263.         }
  264.     }
  265.     if (itemHit == 2)
  266.     {
  267.         DisposeDialog(myDialog);
  268.         SetPort(savePort);
  269.         return;
  270.     }
  271.     
  272.     GetDialogItem(myDialog, 3, &iType, &iHandle, &iRect);
  273.     GetDialogItemText(iHandle, theString);
  274.     StringToNum(theString, &gMaxGens);
  275.     gMaxGens = gMaxGens & 0x0000FFFF;/*limit to 64k generations*/
  276.     if (gMaxGens == 0)
  277.         gMaxGens =1;
  278.         
  279.     GetDialogItem(myDialog, 4, &iType, &iHandle, &iRect);
  280.     GetDialogItemText(iHandle, theString);
  281.     StringToNum(theString, &stringvalue);
  282.     gLifeSize.h = stringvalue & 0x000003FF;
  283.     
  284.     GetDialogItem(myDialog, 5, &iType, &iHandle, &iRect);
  285.     GetDialogItemText(iHandle, theString);
  286.     StringToNum(theString, &stringvalue);
  287.     gLifeSize.v = stringvalue & 0x000001FF;
  288.     if (gLifeSize.h < 3)
  289.         gLifeSize.h = 3;
  290.         
  291.     if ( gLifeSize.v < 3)
  292.         gLifeSize.v = 3;    
  293.     
  294.     GetDialogItem(myDialog, 39, &iType, &iHandle, &iRect);
  295.     GetDialogItemText(iHandle, theString);
  296.     StringToNum(theString, &stringvalue);
  297.     gInterStep = stringvalue & 0x00000FFF;
  298.  
  299.     GetDialogItem(myDialog, 9, &iType, &iHandle, &iRect);
  300.     gRecord = GetControlValue((ControlHandle)iHandle);
  301.  
  302.     GetDialogItem(myDialog, 10, &iType, &iHandle, &iRect);
  303.     gIntermediate = GetControlValue((ControlHandle)iHandle);
  304.  
  305.     gBirth = 0;
  306.     for (itemHit = 0; itemHit <= 8; itemHit++)
  307.     {
  308.         GetDialogItem(myDialog, 11 + itemHit * 2, &iType, &iHandle, &iRect);
  309.         gBirth += GetControlValue((ControlHandle)iHandle) << itemHit;
  310.     }
  311.  
  312.     gDeath = 0;
  313.     for (itemHit = 0; itemHit <= 8; itemHit++)
  314.     {
  315.         GetDialogItem(myDialog, 12 + itemHit * 2, &iType, &iHandle, &iRect);
  316.         gDeath += GetControlValue((ControlHandle)iHandle) << itemHit;
  317.     }
  318.     SetPort(savePort);
  319.     DisposeDialog(myDialog);
  320.     if ((previousSize.h != gLifeSize.h) || (previousSize.v != gLifeSize.v) ||
  321.         (prevBirth != gBirth) || (prevDeath != gDeath) || (prevMax != gMaxGens))
  322.     {
  323.         if (gInitialState.portBits.baseAddr != nil)
  324.             DisposePtr(gInitialState.portBits.baseAddr);
  325.         if (gPreviousState.portBits.baseAddr != nil)
  326.             DisposePtr(gPreviousState.portBits.baseAddr);
  327.         if (gCurrentState.portBits.baseAddr != nil)
  328.             DisposePtr(gCurrentState.portBits.baseAddr);
  329.         gInitialState.portBits.baseAddr = nil;
  330.         gPreviousState.portBits.baseAddr = nil;
  331.         gCurrentState.portBits.baseAddr = nil;
  332.     
  333.         if (gLifeW != nil)
  334.         {
  335.             GetPort(&savePort);
  336.             SetPort(gLifeW);
  337.             EraseRect(&((GrafPtr)gLifeW)->portRect);
  338.             SetPort(savePort);
  339.         }
  340.     }
  341. }
  342.  
  343.  
  344.  
  345.  
  346. void OpenFile(void)
  347. {
  348.     OSErr        iErr;
  349.     GrafPtr    savePort;
  350.     long        fileRuns;
  351.     BitMapStep    startCells;
  352.  
  353.     if (gLifeFile != 0)
  354.         CloseLifeFile(&gLifeFile);
  355.     CloseFile();
  356.     
  357.     iErr = OpenLifeFile(&gLifeFile, &gLifeSpec);
  358.     if (iErr)
  359.         return;
  360.     if (gLifeW == nil)
  361.     {
  362.     gLifeW = NewWindow(nil, &defaultRect, gLifeSpec.name, false, documentProc, 
  363.                                     (WindowPtr) -1, true, 0);
  364.         if (gLifeW == nil)
  365.         {
  366.             gQuit = true;    /*big trouble, so quit    */
  367.             return;
  368.         }
  369.     }
  370.     
  371.     SetWTitle(gLifeW, gLifeSpec.name);
  372.     if (gInitialState.portBits.baseAddr == nil)
  373.     {
  374.         iErr = GetRunNumber(gLifeFile, &fileRuns);
  375.         if (iErr || (fileRuns <= 0))
  376.             return;
  377.         iErr = ReadLifeRun(gLifeFile,&gLifeRun, 1);
  378.         gMaxGens = gLifeRun.maxGen;
  379.         gBirth = gLifeRun.birthRules;
  380.         gDeath = gLifeRun.deathRules;
  381.  
  382.         SetPt(&gLifeSize, gLifeRun.worldSize.right - gLifeRun.worldSize.left, 
  383.                     gLifeRun.worldSize.bottom - gLifeRun.worldSize.top);
  384.         iErr = ReadLifeWorld(gLifeFile, &startCells, 1, 1);
  385.         gInitialState.portBits = startCells.cellsBM;
  386.         gDisplayState = 1;
  387.  
  388. /*    Bob's code    */
  389. {Point hvRatio;
  390. short ratio;
  391.  
  392.     gDisplayRect = defaultRect;
  393.     gDisplayRect.left += gMessageZone.h + 1;
  394.     gDisplayRect.top += gMessageZone.v + 1;
  395.     ratio = GiveRatio(&gInitialState, &gDisplayRect, &hvRatio);
  396.     
  397.     if (ratio == 0)
  398.     {
  399.         SizeWindow(gLifeW,defaultRect.right - defaultRect.left,
  400.                     defaultRect.bottom - defaultRect.top, true);
  401.     } else
  402.     {
  403.         SizeWindow(gLifeW,ratio*(gLifeSize.h + 2) + gMessageZone.h + 1,
  404.                     ratio*(gLifeSize.v + 2) + gMessageZone.v + 1, true);
  405.     }
  406.     ShowWindow(gLifeW);
  407. }
  408.  
  409.         if (iErr)
  410.             return;
  411.         GetPort(&savePort);
  412.         SetPort(&gInitialState);
  413.         SetPortBits(&startCells.cellsBM);
  414.         gDisplayRect = ((GrafPtr)gLifeW)->portRect;
  415.         gDisplayRect.top += gMessageZone.v + 1;
  416.         gDisplayRect.left += gMessageZone.h + 1;
  417. //        DisplayCells(&gInitialState, gLifeW, &gDisplayRect);
  418.         gInitialSaved = gCurrentSaved = true;
  419.         gCurGen = 0;
  420.         SetPort(savePort);
  421.     }
  422. }
  423.  
  424. void CloseFile(void)
  425. {
  426.     BitMapStep    newStep;
  427.     LifeRun        newRun;
  428.     OSErr            iErr;
  429.     DialogPtr    myDialog;
  430.     short            itemHit;
  431.     
  432.     if (gRecord && (gLifeFile == 0) && (gInitialState.portBits.baseAddr != nil))
  433.     {    /* propose the user to create a file    */
  434.         myDialog = GetNewDialog(129, nil, (WindowPtr)-1);
  435.         if (myDialog == nil)
  436.             return;
  437.         SetDialogDefaultItem(myDialog, 1);
  438.         SetDialogCancelItem(myDialog, 3);
  439.  
  440.         ModalDialog(nil, &itemHit);
  441.         DisposeDialog(myDialog);
  442.         switch (itemHit)
  443.         {
  444.             case 1:
  445.                 iErr = CreateLifeFile(&gLifeFile, &gLifeSpec);
  446.                 break;
  447.             case 2:
  448.                 iErr = OpenLifeFile(&gLifeFile, &gLifeSpec);
  449.                 if ((iErr) || (gLifeFile == 0))
  450.                     return;
  451.                 break;
  452.             case 3:
  453.                 gRecord = false;
  454.                 break;
  455.             default:
  456.                 break;
  457.         }
  458.     }
  459.  
  460.  
  461.     if ((!gInitialSaved || !gCurrentSaved) && (gLifeFile != 0) && gRecord)
  462.     {    /* propose the user to create a file    */
  463.         if ((!gInitialSaved) && (gInitialState.portBits.baseAddr != nil))
  464.         {
  465.             newRun.maxGen = gMaxGens;
  466.             newRun.birthRules = gBirth;
  467.             newRun.deathRules = gDeath;
  468.             newRun.filler1 = 0;
  469.             newRun.computedGen = 0;
  470.             newRun.rbytes = gInitialState.portBits.rowBytes;
  471.             newRun.worldSize = gInitialState.portBits.bounds;
  472.             newRun.steps = 0;
  473.             iErr = AppendLifeRun(gLifeFile, &newRun);
  474.     
  475.             newStep.stepvalue = 0;    /* 0 = initial state    */
  476.             newStep.cellsBM = gInitialState.portBits;
  477.             if (!AppendLifeWorld(gLifeFile, &newStep))
  478.                 gInitialSaved = true;
  479.         }
  480.         
  481.         if ((!gCurrentSaved) && (gCurrentState.portBits.baseAddr != nil))
  482.         {
  483.             newStep.stepvalue = gCurGen;    /* 0 = initial state    */
  484.             newStep.cellsBM = gCurrentState.portBits;
  485.             if (!AppendLifeWorld(gLifeFile, &newStep))
  486.                 gCurrentSaved = true;
  487.         }
  488.     }
  489.     
  490.     if (gInitialState.portBits.baseAddr != nil)
  491.         DisposePtr(gInitialState.portBits.baseAddr);
  492.     if (gPreviousState.portBits.baseAddr != nil)
  493.         DisposePtr(gPreviousState.portBits.baseAddr);
  494.     if (gCurrentState.portBits.baseAddr != nil)
  495.         DisposePtr(gCurrentState.portBits.baseAddr);
  496.     gInitialState.portBits.baseAddr = nil;
  497.     gPreviousState.portBits.baseAddr = nil;
  498.     gCurrentState.portBits.baseAddr = nil;
  499.     
  500.     if (gLifeW != nil)
  501.         DisposeWindow(gLifeW);
  502.     gLifeW = nil;
  503.      
  504.     CloseLifeFile(&gLifeFile);
  505.     gDisplayState = 0;
  506.     gInTest = false;
  507. }
  508.  
  509. void DoSave(void)
  510. {
  511.     OSErr        iErr;
  512.     BitMapStep    newStep;
  513.     LifeRun    newRun;
  514.  
  515.     
  516.     if (gInitialState.portBits.baseAddr == nil)
  517.         return;
  518.     if (gCurrentSaved && gInitialSaved && (gLifeFile != 0))
  519.         return;
  520.     
  521.     if (gLifeFile == 0)
  522.     {
  523.         sprintf((char*)gLifeSpec.name, (char*)"\pUntitled");
  524.         iErr = CreateLifeFile(&gLifeFile, &gLifeSpec);
  525.         if (iErr)
  526.             return;
  527.     }
  528.     if (gLifeW)    /*is that necessary???    */
  529.         SetWTitle(gLifeW, gLifeSpec.name);
  530.     if ((!gInitialSaved) && (gInitialState.portBits.baseAddr != nil))
  531.     {
  532.         newRun.maxGen = gMaxGens;
  533.         newRun.birthRules = gBirth;
  534.         newRun.deathRules = gDeath;
  535.         newRun.filler1 = 0;
  536.         newRun.computedGen = 0;
  537.         newRun.rbytes = gInitialState.portBits.rowBytes;
  538.         newRun.worldSize = gInitialState.portBits.bounds;
  539.         newRun.steps = 0;
  540.         iErr = AppendLifeRun(gLifeFile, &newRun);
  541.         
  542.         newStep.stepvalue = 0;    /* 0 = initial state    */
  543.         newStep.cellsBM = gInitialState.portBits;
  544.         if (!AppendLifeWorld(gLifeFile, &newStep))
  545.             gInitialSaved = true;
  546.     }
  547.                 
  548.     if ((!gCurrentSaved) && (gCurrentState.portBits.baseAddr != nil))
  549.     {
  550.         newStep.stepvalue = gCurGen;    /* 0 = initial state    */
  551.         newStep.cellsBM = gCurrentState.portBits;
  552.         iErr = AppendLifeWorld(gLifeFile, &newStep);
  553.         if (!iErr)
  554.             gCurrentSaved = true;
  555.     }
  556. }
  557.  
  558. void AppendtoFile(void)
  559. {
  560.     if (gInitialState.portBits.baseAddr == nil)
  561.         return;
  562.     if (gLifeFile != 0)
  563.         CloseLifeFile(&gLifeFile);
  564.     
  565.     if (!OpenLifeFile(&gLifeFile, &gLifeSpec))
  566.     {
  567.         gInitialSaved = gCurrentSaved = false;
  568.         DoSave();
  569.     }    
  570. }
  571.  
  572. void PropagateCurrent()
  573. {
  574.     DialogPtr    myDialog;
  575.     OSErr            iErr;
  576.     short            itemHit;
  577.     LifeRun        newRun;
  578.     BitMapStep    newStep;
  579.     long            numRuns;
  580.     Rect            messageRect;
  581.     
  582.     
  583.     if ((gInitialState.portBits.baseAddr == nil) || (gLifeW == nil))
  584.         NewRun();
  585.     if ((gInitialState.portBits.baseAddr == nil) || (gLifeW == nil))
  586.         return;
  587.  
  588. /*Make a copy of the cells    */
  589.     gCurrentState.portBits = gInitialState.portBits;
  590.     gCurrentState.portBits.baseAddr = NewPtr(gCurrentState.portBits.rowBytes * 
  591.                                                         gLifeSize.v);
  592.     BlockMoveData(gInitialState.portBits.baseAddr,
  593.         gCurrentState.portBits.baseAddr, GetPtrSize(gCurrentState.portBits.baseAddr));
  594.     
  595.     if (gPreviousState.portBits.baseAddr != nil)
  596.         DisposePtr(gPreviousState.portBits.baseAddr);
  597.     gPreviousState.portBits.baseAddr = nil;
  598.     
  599. /*    Call User solution on current bitmap    */
  600.     Microseconds(&mbefore);
  601.     gCurGen = PropagateLife(gCurrentState.portBits, gMaxGens, gBirth, gDeath);
  602.     Microseconds(&mafter);
  603.     mdiff = mafter.lo - mbefore.lo;
  604.     gCurrentSaved = false;
  605.  
  606.     gDisplayRect = ((GrafPtr)gLifeW)->portRect;
  607.     gDisplayRect.top += gMessageZone.v + 1;
  608.     gDisplayRect.left += gMessageZone.h + 1;
  609.     DisplayCells(&gCurrentState, gLifeW, &gDisplayRect);
  610.     gDisplayState = 2;
  611.  
  612.  
  613.     sprintf((char*)gMessage1, 
  614.             (char*)"\p Your routine computed %ld generations.", gCurGen);
  615.     sprintf((char*)gMessage2, (char*)"\p");
  616.  
  617. /*invalidate whole window to force solution display    */
  618.     SetPort(gLifeW);
  619.     messageRect = ((GrafPtr)gLifeW)->portRect;
  620.     messageRect.bottom = gMessageZone.v;
  621.     InvalRect(&messageRect);
  622.  
  623.  
  624.  
  625.  
  626. /*the two rects always overlap now    */
  627.         
  628. /* saving stuff    */
  629.     sprintf((char*)gLifeSpec.name, (char*)"\pUntitled");
  630.     if (gRecord && (gLifeFile == 0))
  631.     {    /* propose the user to create a file    */
  632.         myDialog = GetNewDialog(129, nil, (WindowPtr)-1);
  633.         if (myDialog == nil)
  634.             return;
  635.         SetDialogDefaultItem(myDialog, 1);
  636.         SetDialogCancelItem(myDialog, 3);
  637.  
  638.         ModalDialog(nil, &itemHit);
  639.         DisposeDialog(myDialog);
  640.         switch (itemHit)
  641.         {
  642.             case 1:
  643.                 iErr = CreateLifeFile(&gLifeFile, &gLifeSpec);
  644.                 if ((iErr) || (gLifeFile == 0))
  645.                     return;
  646.                 break;
  647.             case 2:
  648.                 iErr = OpenLifeFile(&gLifeFile, &gLifeSpec);
  649.                 if ((iErr) || (gLifeFile == 0))
  650.                     return;
  651.                 break;
  652.             case 3:
  653.                 gRecord = false;
  654.                 break;
  655.             default:
  656.                 break;
  657.         }
  658.     }
  659.     if (gRecord)
  660.     {
  661.         if ((!gInitialSaved) && (gInitialState.portBits.baseAddr != nil))
  662.         {
  663.             newRun.maxGen = gMaxGens;
  664.             newRun.birthRules = gBirth;
  665.             newRun.deathRules = gDeath;
  666.             newRun.filler1 = 0;
  667.             newRun.computedGen = 0;
  668.             newRun.rbytes = gInitialState.portBits.rowBytes;
  669.             newRun.worldSize = gInitialState.portBits.bounds;
  670.             newRun.steps = 0;
  671.             if (AppendLifeRun(gLifeFile, &newRun))
  672.                 return;
  673.             newStep.stepvalue = 0;    /* 0 = initial state    */
  674.             newStep.cellsBM = gInitialState.portBits;
  675.             if (!AppendLifeWorld(gLifeFile, &newStep))
  676.                 gInitialSaved = true;
  677.         }
  678.         
  679.         if ((!gCurrentSaved) && (gCurrentState.portBits.baseAddr != nil))
  680.         {
  681.             newStep.stepvalue = gCurGen;    /* 0 = initial state    */
  682.             newStep.cellsBM = gCurrentState.portBits;
  683.             if (!AppendLifeWorld(gLifeFile, &newStep))
  684.             {
  685.                 if (GetRunNumber(gLifeFile, &numRuns))
  686.                     return;
  687.                 SetComputedGen(gLifeFile, numRuns, gCurGen);
  688.                 gCurrentSaved = true;
  689.             }
  690.         }
  691.     }
  692. }
  693.  
  694. void NewRun(void)
  695. {
  696. //    Rect            wRect;
  697.     GrafPtr        savePort;
  698.     short            width, rbytes;
  699.     OSErr            iErr;
  700.     DialogPtr    myDialog;
  701.     short            itemHit;
  702.     LifeRun        newRun;
  703.     BitMapStep    newStep;
  704.     
  705. /* If gRecord is set and no file is open, ask user what to do    */
  706.     sprintf((char*)gLifeSpec.name, (char*)"\pUntitled");
  707.     if (gRecord && (gLifeFile == 0))
  708.     {    /* propose the user to create a file    */
  709.         myDialog = GetNewDialog(129, nil, (WindowPtr)-1);
  710.         if (myDialog == nil)
  711.             return;
  712.         SetDialogDefaultItem(myDialog, 1);
  713.         SetDialogCancelItem(myDialog, 3);
  714.  
  715.         ModalDialog(nil, &itemHit);
  716.         DisposeDialog(myDialog);
  717.         switch (itemHit)
  718.         {
  719.             case 1:
  720.                 iErr = CreateLifeFile(&gLifeFile, &gLifeSpec);
  721.                 if ((iErr) || (gLifeFile == 0))
  722.                     return;
  723.                 break;
  724.             case 2:
  725.                 iErr = OpenLifeFile(&gLifeFile, &gLifeSpec);
  726.                 if ((iErr) || (gLifeFile == 0))
  727.                     return;
  728.                 break;
  729.             case 3:
  730.                 gRecord = false;
  731.                 break;
  732.             default:
  733.                 break;
  734.         }
  735.     }
  736.     gInTest = false;    /* for some cases, since the code is not well segmented*/
  737.  
  738. // Create the window if necessary
  739. //    wRect = defaultRect;
  740.     if (gLifeW == nil)
  741.     {
  742.         gLifeW = NewWindow(nil, &defaultRect, gLifeSpec.name, false, documentProc, 
  743.                                     (WindowPtr) -1, true, 0);
  744.         if (gLifeW == nil)
  745.         {    
  746.             gQuit = true;
  747.             return;
  748.         }
  749.     }
  750.     
  751.     if (gInitialState.portBits.baseAddr != nil)
  752.         DisposePtr(gInitialState.portBits.baseAddr);
  753.     if (gPreviousState.portBits.baseAddr != nil)
  754.         DisposePtr(gPreviousState.portBits.baseAddr);
  755.     if (gCurrentState.portBits.baseAddr != nil)
  756.         DisposePtr(gCurrentState.portBits.baseAddr);
  757.     gInitialState.portBits.baseAddr = nil;
  758.     gPreviousState.portBits.baseAddr = nil;
  759.     gCurrentState.portBits.baseAddr = nil;
  760.  
  761.  
  762.     width = gLifeSize.h;
  763.     if (width % 32 > 0)
  764.         width += (32 - (width) % 32);    /* should be 32 bits flush */
  765.     rbytes = width / 8;
  766.  
  767.     gInitialState.portBits.rowBytes = rbytes;
  768.     SetRect(&gInitialState.portBits.bounds, 0, 0, gLifeSize.h, gLifeSize.v);
  769.     gInitialState.portBits.baseAddr = NewPtrClear(rbytes * gLifeSize.v);
  770.     if (gInitialState.portBits.baseAddr == nil) 
  771.         return;    /*error handling maybe ? */
  772.     gDisplayState = 1;
  773.  
  774. /* resize window to match problem size */
  775. {Point hvRatio;
  776. short ratio;
  777.  
  778.     gDisplayRect = defaultRect;
  779.     gDisplayRect.left += gMessageZone.h + 1;
  780.     gDisplayRect.top += gMessageZone.v + 1;
  781.     ratio = GiveRatio(&gInitialState, &gDisplayRect, &hvRatio);
  782.  
  783.     if (ratio == 0)
  784.     {
  785.         SizeWindow(gLifeW,defaultRect.right - defaultRect.left,
  786.                     defaultRect.bottom - defaultRect.top, true);
  787.     } else
  788.     {
  789.         SizeWindow(gLifeW,ratio*(gLifeSize.h + 2) + gMessageZone.h + 1,
  790.                     ratio*(gLifeSize.v + 2) + gMessageZone.v + 1, true);
  791.     }
  792.     ShowWindow(gLifeW);
  793. }
  794.     GetPort(&savePort);
  795.     SetPort(&gInitialState);
  796.  
  797. #if _UseInitCells_
  798.     InitCellsPort(&gInitialState);
  799. #endif
  800.  
  801.     SetPort(gLifeW);
  802.     gDisplayRect = ((GrafPtr)gLifeW)->portRect;
  803.     gDisplayRect.top += gMessageZone.v + 1;
  804.     gDisplayRect.left += gMessageZone.h + 1;
  805.     EraseRect(&((GrafPtr)gLifeW)->portRect);    /* erase old initial rect    */
  806.     InvalRect(&((GrafPtr)gLifeW)->portRect);
  807.     gDisplayState = 1;
  808.     
  809. //    DisplayCells(&gInitialState, gLifeW, &gDisplayRect);
  810.     gCurGen = 0;
  811.     gInitialSaved = false;
  812.     gCurrentSaved = true; /*doesn't exist yet */
  813. /* Save to file if necessary    */
  814.     if (gRecord)
  815.     {
  816.         newRun.maxGen = gMaxGens;
  817.         newRun.birthRules = gBirth;
  818.         newRun.deathRules = gDeath;
  819.         newRun.filler1 = 0;
  820.         newRun.computedGen = 0;
  821.         newRun.rbytes = rbytes;
  822.         newRun.worldSize = gInitialState.portBits.bounds;
  823.         newRun.steps = 0;
  824.         iErr = AppendLifeRun(gLifeFile, &newRun);
  825. /* some error handling is missing here    */
  826.         newStep.stepvalue = 0;    /* 0 = initial state    */
  827.         newStep.cellsBM = gInitialState.portBits;
  828.         iErr = AppendLifeWorld(gLifeFile, &newStep);
  829.         gInitialSaved = gCurrentSaved = true;
  830.     }
  831.     SetPort(savePort);
  832. }
  833.  
  834. void PropagateCurrentbyOne()
  835. {
  836.     DialogPtr    myDialog;
  837.     OSErr            iErr;
  838.     short            itemHit;
  839.     LifeRun        newRun;
  840.     BitMapStep    newStep;
  841.     
  842.     if ((gInitialState.portBits.baseAddr == nil) || (gLifeW == nil))
  843.         NewRun();
  844.     if ((gInitialState.portBits.baseAddr == nil) || (gLifeW == nil))
  845.         return;
  846.     gDisplayState = 1;
  847.  
  848. /*Make a copy of the cells    */
  849.     if (gCurrentState.portBits.baseAddr == nil)
  850.     {
  851.         gCurrentState.portBits = gInitialState.portBits;
  852.         gCurrentState.portBits.baseAddr = NewPtr(gCurrentState.portBits.rowBytes * 
  853.                                                         gLifeSize.v);
  854.         if (gCurrentState.portBits.baseAddr == nil)
  855.             return;
  856.         BlockMoveData(gInitialState.portBits.baseAddr,
  857.         gCurrentState.portBits.baseAddr, GetPtrSize(gCurrentState.portBits.baseAddr));
  858.     }
  859.     if (gPreviousState.portBits.baseAddr != nil)
  860.         DisposePtr(gPreviousState.portBits.baseAddr);
  861.     gPreviousState.portBits = gCurrentState.portBits;
  862.     gPreviousState.portBits.baseAddr = 
  863.                     NewPtr(gCurrentState.portBits.rowBytes * gLifeSize.v);
  864.     if (gPreviousState.portBits.baseAddr == nil)
  865.         return;
  866.     BlockMoveData(gCurrentState.portBits.baseAddr,
  867.                     gPreviousState.portBits.baseAddr, 
  868.                     GetPtrSize(gPreviousState.portBits.baseAddr));
  869.     
  870. /*    Call User solution on current bitmap with one generation maximum*/
  871.     Microseconds(&mbefore);
  872.     gCurGen = PropagateLife(gCurrentState.portBits, 1, gBirth, gDeath);
  873.     Microseconds(&mafter);
  874.     mdiff = mafter.lo - mbefore.lo;
  875.     gCurrentSaved = false;
  876.     
  877.     gDisplayState = 2;
  878.  
  879.     gDisplayRect = ((GrafPtr)gLifeW)->portRect;
  880.     gDisplayRect.top += gMessageZone.v + 1;
  881.     gDisplayRect.left += gMessageZone.h + 1;
  882.  
  883.     DisplayCells(&gCurrentState, gLifeW, &gDisplayRect);
  884. /*the two rects always overlap in this version    */
  885.     
  886. /* saving stuff    */
  887.     sprintf((char*)gLifeSpec.name, (char*)"\pUntitled");
  888.     if (gRecord && (gLifeFile == 0))
  889.     {    /* propose the user to create a file    */
  890.         myDialog = GetNewDialog(129, nil, (WindowPtr)-1);
  891.         if (myDialog == nil)
  892.             return;
  893.         SetDialogDefaultItem(myDialog, 1);
  894.         SetDialogCancelItem(myDialog, 3);
  895.  
  896.         ModalDialog(nil, &itemHit);
  897.         DisposeDialog(myDialog);
  898.         switch (itemHit)
  899.         {
  900.             case 1:
  901.                 iErr = CreateLifeFile(&gLifeFile, &gLifeSpec);
  902.                 if ((iErr) || (gLifeFile == 0))
  903.                     return;
  904.                 break;
  905.             case 2:
  906.                 iErr = OpenLifeFile(&gLifeFile, &gLifeSpec);
  907.                 if ((iErr) || (gLifeFile == 0))
  908.                     return;
  909.                 break;
  910.             case 3:
  911.                 gRecord = false;
  912.                 break;
  913.             default:
  914.                 break;
  915.         }
  916.     }
  917.     if (gRecord)
  918.     {
  919.         if ((!gInitialSaved) && (gInitialState.portBits.baseAddr != nil))
  920.         {
  921.             newRun.maxGen = gMaxGens;
  922.             newRun.birthRules = gBirth;
  923.             newRun.deathRules = gDeath;
  924.             newRun.filler1 = 0;
  925.             newRun.computedGen = 0;
  926.             newRun.rbytes = gInitialState.portBits.rowBytes;
  927.             newRun.worldSize = gInitialState.portBits.bounds;
  928.             newRun.steps = 0;
  929.             if (AppendLifeRun(gLifeFile, &newRun))
  930.                 return;
  931.             newStep.stepvalue = 0;    /* 0 = initial state    */
  932.             newStep.cellsBM = gInitialState.portBits;
  933.             if (!AppendLifeWorld(gLifeFile, &newStep))
  934.                 gInitialSaved = true;
  935.         }
  936.         
  937.         if ((!gCurrentSaved) && (gCurrentState.portBits.baseAddr != nil))
  938.         {
  939.             newStep.stepvalue = gCurGen;    /* 0 = initial state    */
  940.             newStep.cellsBM = gCurrentState.portBits;
  941.             if (!AppendLifeWorld(gLifeFile, &newStep))
  942.                 gCurrentSaved = true;
  943.         }
  944.     }
  945. }
  946.  
  947. void ReturnToInitial(void)
  948. {
  949.     if (gPreviousState.portBits.baseAddr != nil)
  950.         DisposePtr(gPreviousState.portBits.baseAddr);
  951.     if (gCurrentState.portBits.baseAddr != nil)
  952.         DisposePtr(gCurrentState.portBits.baseAddr);
  953.     gPreviousState.portBits.baseAddr = nil;
  954.     gCurrentState.portBits.baseAddr = nil;
  955.  
  956.     gDisplayState = 1;
  957.     gInTest = false;    /* for some cases, since the code is not well segmented*/
  958.  
  959.     DisplayCells(&gInitialState, gLifeW, &gDisplayRect);
  960. }
  961.  
  962. void StartFromCurrent(void)
  963. {
  964.  
  965. /*Destroy actual initial data*/
  966.     if (gInitialState.portBits.baseAddr != nil)
  967.         DisposePtr(gInitialState.portBits.baseAddr);
  968.  
  969. /*then set initial state to actual final state    */
  970.     if (gCurrentState.portBits.baseAddr != nil)
  971.         gInitialState.portBits = gCurrentState.portBits;
  972. /*Destroy Any Previous state if necessary    */    
  973.     if (gPreviousState.portBits.baseAddr != nil)
  974.         DisposePtr(gPreviousState.portBits.baseAddr);
  975.  
  976.     gPreviousState.portBits.baseAddr = nil;
  977.     gCurrentState.portBits.baseAddr = nil;
  978.     gInitialSaved = gCurrentSaved = false;
  979.  
  980.     gDisplayState = 1;
  981.     gInTest = false;    /* for some cases, since the code is not well segmented*/
  982.  
  983. }
  984.  
  985.  
  986. /*    Globals flags for testing    */
  987. //Boolean    gInTest
  988. //Boolean    testHasFile = false;
  989. short        testCurRun;
  990. Boolean    testReady;
  991. Boolean    testSolved;
  992. long        runNumber;
  993.  
  994. void TestWholeFile(void)
  995. {
  996.     OSErr        iErr;
  997.     long        bytesCount, *checkPtr;
  998.     Rect        messageRect;
  999.     Boolean    good;
  1000.     
  1001.     BitMapStep    myBMStep;
  1002.     GrafPtr    savePort;
  1003.     
  1004.     if (!gInTest){
  1005.     
  1006.     if (gLifeW != nil)
  1007.         DisposeWindow(gLifeW);
  1008.     gLifeW = nil;
  1009.     
  1010.     CloseLifeFile(&gLifeFile);
  1011.  
  1012.     gDisplayState = 0;
  1013.     
  1014.     OpenFile();
  1015.     if (gLifeFile == 0)
  1016.         return;
  1017.     gInTest = true;
  1018.     
  1019.     iErr = GetRunNumber(gLifeFile, &runNumber);
  1020.     if (runNumber < 1)
  1021.     {
  1022.         gInTest = false;
  1023.         return;
  1024.     }
  1025.     testCurRun = 1;
  1026.     testReady = false;
  1027.     testSolved = false;
  1028.  
  1029.     }
  1030.     
  1031.     if (testCurRun > runNumber)
  1032.     {
  1033.         CloseFile();
  1034.         sprintf((char*)gMessage1, (char*)"\p");
  1035.         sprintf((char*)gMessage2, (char*)"\p");
  1036.         gInTest = false;
  1037.         return;
  1038.     }
  1039.  
  1040.     GetPort(&savePort);
  1041.     
  1042.     if (!testReady)
  1043.     {
  1044.         if (gInitialState.portBits.baseAddr != nil)
  1045.             DisposePtr(gInitialState.portBits.baseAddr);
  1046.         if (gPreviousState.portBits.baseAddr != nil)
  1047.             DisposePtr(gPreviousState.portBits.baseAddr);
  1048.         if (gCurrentState.portBits.baseAddr != nil)
  1049.             DisposePtr(gCurrentState.portBits.baseAddr);
  1050.         if (gTempFinalState.portBits.baseAddr != nil)
  1051.             DisposePtr(gTempFinalState.portBits.baseAddr);
  1052.         if (gErrorState.portBits.baseAddr != nil)
  1053.             DisposePtr(gErrorState.portBits.baseAddr);
  1054.         gInitialState.portBits.baseAddr = nil;
  1055.         gPreviousState.portBits.baseAddr = nil;
  1056.         gCurrentState.portBits.baseAddr = nil;
  1057.         gTempFinalState.portBits.baseAddr = nil;
  1058.         gErrorState.portBits.baseAddr = nil;
  1059.  
  1060.         if (ReadLifeRun(gLifeFile, &gLifeRun, testCurRun))
  1061.         {
  1062.             gDisplayState = 0;
  1063.             gInTest = false;
  1064.             SetPort(savePort);
  1065.             return;
  1066.         }
  1067.         if (gLifeRun.steps >= 1)
  1068.         {
  1069.             gBirth = gLifeRun.birthRules;
  1070.             gDeath = gLifeRun.deathRules;
  1071.             gMaxGens = gLifeRun.maxGen;
  1072.             SetPt(&gLifeSize, gLifeRun.worldSize.right - gLifeRun.worldSize.left, 
  1073.                         gLifeRun.worldSize.bottom - gLifeRun.worldSize.top);
  1074.             
  1075.             iErr = ReadLifeWorld(gLifeFile, &myBMStep, testCurRun, 1);
  1076.             if (myBMStep.stepvalue != 0)
  1077.             {
  1078.                 testCurRun++;
  1079.                 SetPort(savePort);
  1080.                 return;
  1081.             }
  1082.             SetPort(&gInitialState);
  1083.             SetPortBits(&myBMStep.cellsBM);
  1084.  
  1085. {Point hvRatio;
  1086. short ratio;
  1087.  
  1088.     gDisplayRect = defaultRect;
  1089.     gDisplayRect.left += gMessageZone.h + 1;
  1090.     gDisplayRect.top += gMessageZone.v + 1;
  1091.     ratio = GiveRatio(&gInitialState, &gDisplayRect, &hvRatio);
  1092.  
  1093.     if (ratio == 0)
  1094.     {
  1095.         SizeWindow(gLifeW,defaultRect.right - defaultRect.left,
  1096.                     defaultRect.bottom - defaultRect.top, true);
  1097.     } else
  1098.     {
  1099.         SizeWindow(gLifeW,ratio*(gLifeSize.h + 2) + gMessageZone.h + 1,
  1100.                     ratio*(gLifeSize.v + 2) + gMessageZone.v + 1, true);
  1101.     }
  1102.     SetPort(gLifeW);
  1103.     EraseRect(&((GrafPtr)gLifeW)->portRect);
  1104. }
  1105.  
  1106.             iErr = ReadLifeWorld(gLifeFile, &myBMStep, testCurRun, gLifeRun.steps);
  1107.             if (myBMStep.stepvalue != gLifeRun.computedGen)
  1108.             {
  1109.                 testCurRun++;
  1110.                 SetPort(savePort);
  1111.                 return;
  1112.             }
  1113.             SetPort(&gTempFinalState);
  1114.             SetPortBits(&myBMStep.cellsBM);
  1115.  
  1116.             gCurrentState.portBits = gInitialState.portBits;
  1117.             gCurrentState.portBits.baseAddr = 
  1118.                         NewPtr(gCurrentState.portBits.rowBytes * 
  1119.                                 gCurrentState.portBits.bounds.bottom - 
  1120.                                 gCurrentState.portBits.bounds.top);
  1121.             if (gCurrentState.portBits.baseAddr == nil)
  1122.             {
  1123.                 testCurRun++;
  1124.                 return;
  1125.                 SetPort(savePort);
  1126.             }
  1127.             BlockMoveData(gInitialState.portBits.baseAddr,
  1128.                         gCurrentState.portBits.baseAddr, 
  1129.                         GetPtrSize(gCurrentState.portBits.baseAddr));
  1130.  
  1131.             gDisplayRect = ((GrafPtr)gLifeW)->portRect;
  1132.             gDisplayRect.top += gMessageZone.v + 1;
  1133.             gDisplayRect.left += gMessageZone.h + 1;
  1134.  
  1135.             sprintf((char*)gMessage1, (char*)"\pPress Command-T to submit run to your Solution routine.");
  1136.             sprintf((char*)gMessage2, (char*)"\p");
  1137.  
  1138. /*invalidate whole window to force solution display    */
  1139.             SetPort(gLifeW);
  1140.             InvalRect(&((GrafPtr)gLifeW)->portRect);
  1141.  
  1142.             testReady = true;
  1143.             gDisplayState = 1;
  1144.             SetPort(savePort);
  1145.             return;
  1146.         }
  1147.     }
  1148.     
  1149.     if (!testSolved)
  1150.     {
  1151. /*    Now Test the user solution    */
  1152.         gCurGen = PropagateLife(gCurrentState.portBits, gMaxGens, gBirth, gDeath);
  1153.         gDisplayState = 2;
  1154. //        DisplayCells(&gCurrentState, gLifeW, &gDisplayRect);
  1155.             
  1156. /* gPreviousState will hold the copy of the solution used for checking    */
  1157.         gErrorState.portBits = gCurrentState.portBits;
  1158.         gErrorState.portBits.baseAddr = NewPtr(gErrorState.portBits.rowBytes * 
  1159.                 gErrorState.portBits.bounds.bottom - gErrorState.portBits.bounds.top);
  1160. /*        BlockMoveData(gCurrentState.portBits.baseAddr,
  1161.         gErrorState.portBits.baseAddr, GetPtrSize(gErrorState.portBits.baseAddr));
  1162. */
  1163.         CopyBits(&gCurrentState.portBits, &gErrorState.portBits, 
  1164.                     &gTempFinalState.portBits.bounds, &gErrorState.portBits.bounds,
  1165.                     srcCopy, gErrorState.clipRgn);        
  1166.  
  1167.         CopyBits(&gTempFinalState.portBits, &gErrorState.portBits, 
  1168.                     &gTempFinalState.portBits.bounds, &gErrorState.portBits.bounds,
  1169.                     srcXor, gErrorState.clipRgn);        
  1170.             
  1171.         bytesCount = gErrorState.portBits.rowBytes * 
  1172.                         (gErrorState.portBits.bounds.bottom - 
  1173.                             gErrorState.portBits.bounds.top);
  1174.         good = true;
  1175.         for (checkPtr = (long*)gErrorState.portBits.baseAddr;
  1176.                                         bytesCount > 0; bytesCount -= 4)
  1177.         {
  1178.             if (*checkPtr++)
  1179.             {
  1180.                 good = false;
  1181.                 goto message;
  1182.             }
  1183.         }
  1184. message:
  1185.         if (good)
  1186.         {
  1187.     sprintf((char*)gMessage1, (char*)"\pSolution is correct. Press Command-T to continue");
  1188.     sprintf((char*)gMessage2, (char*)"\p");
  1189.         } else
  1190.         {
  1191.     sprintf((char*)gMessage1, (char*)"\pSolution is INCORRECT. Press Command-T to continue");
  1192.     sprintf((char*)gMessage2, (char*)"\por use the different menus to display some related bitmaps");
  1193.         }
  1194.         SetPort(gLifeW);
  1195.         messageRect = ((GrafPtr)gLifeW)->portRect;
  1196. /*invalidate whole window to force solution display    */
  1197.         InvalRect(&messageRect);
  1198.         
  1199.         testSolved = true;
  1200.         testCurRun++;
  1201.     }
  1202.     if (testSolved && testReady)
  1203.         { testSolved = testReady = false;}
  1204.  
  1205.  
  1206.     SetPort(savePort);
  1207. }
  1208.  
  1209.  
  1210.  
  1211. void UpdateLifeWindow(void)
  1212. {
  1213.     Rect    messageRect;
  1214.     GrafPtr    savePort;
  1215.     
  1216.     switch (gDisplayState)
  1217.     {
  1218.     case 1:
  1219.         DisplayCells(&gInitialState, gLifeW, &gDisplayRect);
  1220.         break;
  1221.     case 2:
  1222.         DisplayCells(&gCurrentState, gLifeW, &gDisplayRect);
  1223.         break;
  1224.     case 3:
  1225.         DisplayCells(&gPreviousState, gLifeW, &gDisplayRect);
  1226.         break;
  1227.     case 4:
  1228.         DisplayCells(&gTempFinalState, gLifeW, &gDisplayRect);
  1229.         break;
  1230.     case 5:
  1231.         DisplayCells(&gErrorState, gLifeW, &gDisplayRect);
  1232.         break;
  1233.     default:
  1234.         DisplayCells(&gInitialState, gLifeW, &gDisplayRect);/*will erase all*/
  1235.         break;
  1236.     }
  1237.     messageRect = ((GrafPtr)gLifeW)->portRect;
  1238.     messageRect.bottom = gMessageZone.v;
  1239.     GetPort(&savePort);
  1240.     SetPort(gLifeW);
  1241.     EraseRect(&messageRect);
  1242.     MoveTo(15, 20);
  1243.     DrawString(gMessage1);
  1244.     MoveTo(15, 40);
  1245.     DrawString(gMessage2);
  1246.     SetPort(savePort);
  1247. }
  1248.  
  1249. void DoNothing()
  1250. {}
  1251.  
  1252. void DoAboutBox(void)
  1253. {
  1254.     short            itemHit;
  1255.     DialogPtr    myDialog;
  1256.     GrafPtr        savePort;
  1257.     
  1258.     myDialog = GetNewDialog(131, nil, (WindowPtr)-1);
  1259.     if (myDialog == nil)
  1260.         return;
  1261.     GetPort(&savePort);
  1262.     SetPort(myDialog);
  1263.     ModalDialog(nil, &itemHit);
  1264.     DisposeDialog(myDialog);
  1265.     
  1266.     SetPort(savePort);
  1267. }
  1268.  
  1269. void PrepareMenus(void)
  1270. {
  1271.     if ((gLifeW != nil) && (gInitialState.portBits.baseAddr != nil))
  1272.     {
  1273.         EnableItem(GetMenuHandle(kFileMenu), kSave);
  1274.         EnableItem(GetMenuHandle(kFileMenu), kAppend);
  1275.  
  1276.         EnableItem(GetMenuHandle(kLifeMenu), kReturnToInitial);
  1277.         EnableItem(GetMenuHandle(kLifeMenu), kStartFromCurrent);
  1278.  
  1279.         EnableItem(GetMenuHandle(kTestMenu), kDisplayInitial);
  1280.         EnableItem(GetMenuHandle(kTestMenu), kDisplayPrevious);
  1281.         EnableItem(GetMenuHandle(kTestMenu), kDisplayCurrent);
  1282.     } else
  1283.     {
  1284.         DisableItem(GetMenuHandle(kFileMenu), kSave);
  1285.         DisableItem(GetMenuHandle(kFileMenu), kAppend);
  1286.  
  1287.         DisableItem(GetMenuHandle(kLifeMenu), kReturnToInitial);
  1288.         DisableItem(GetMenuHandle(kLifeMenu), kStartFromCurrent);
  1289.  
  1290.         DisableItem(GetMenuHandle(kTestMenu), kDisplayInitial);
  1291.         DisableItem(GetMenuHandle(kTestMenu), kDisplayPrevious);
  1292.         DisableItem(GetMenuHandle(kTestMenu), kDisplayCurrent);
  1293.     }
  1294.     
  1295.     if (gLifeW != nil)
  1296.         EnableItem(GetMenuHandle(kFileMenu), kClose);
  1297.     else
  1298.         DisableItem(GetMenuHandle(kFileMenu), kClose);
  1299.         
  1300.     if (gInTest)
  1301.     {    
  1302.         EnableItem(GetMenuHandle(kTestMenu), kDisplayGood);
  1303.         EnableItem(GetMenuHandle(kTestMenu), kDisplayErrors);
  1304.     } else
  1305.     {
  1306.         DisableItem(GetMenuHandle(kTestMenu), kDisplayGood);
  1307.         DisableItem(GetMenuHandle(kTestMenu), kDisplayErrors);
  1308.     }
  1309. }
  1310.  
  1311.  
  1312. void DoMenu(long menusel)
  1313. {    
  1314.     short         menuNumber, itemNumber, daRefNum;
  1315.     Str255        daName;
  1316.     GrafPtr        savePort;
  1317.     
  1318.     itemNumber = LoWord(menusel);
  1319.     menuNumber = HiWord(menusel);
  1320.     
  1321.     switch(menuNumber)
  1322.     {
  1323.         case    kAppleMenu:
  1324.             switch (itemNumber)
  1325.             {
  1326.                 case 1:
  1327.                     DoAboutBox();
  1328.                     break;
  1329.                 default:
  1330.                     GetPort(&savePort);
  1331.                     GetMenuItemText(GetMenuHandle(kAppleMenu), itemNumber, daName);
  1332.                     daRefNum = OpenDeskAcc(daName);
  1333.                     SetPort(savePort);
  1334.                     break;
  1335.             }
  1336.             break;
  1337.         case    kFileMenu:
  1338.             switch (itemNumber)
  1339.             {
  1340.                 case kNew:
  1341.                     NewRun();
  1342.                     break;
  1343.                 case kOpen:
  1344.                     OpenFile();
  1345.                     break;
  1346.                 case kClose:
  1347.                     CloseFile();
  1348.                     break;
  1349.                 case kSave:
  1350.                     DoSave();
  1351.                     break;
  1352.                 case kSaveAs:
  1353.                     DoNothing();
  1354.                 case kAppend:
  1355.                     AppendtoFile();
  1356.                     break;
  1357.                 case kQuit:
  1358.                     gQuit = true;
  1359.                     break;
  1360.                 default:
  1361.                     break;
  1362.             }
  1363.             break;
  1364.         case kLifeMenu:
  1365.             switch (itemNumber)
  1366.             {
  1367.                 case kChangeSettings:
  1368.                     ChangeSettings();
  1369.                     break;
  1370.                 case kPropagate:
  1371.                     PropagateCurrent();
  1372.                     break;
  1373.                 case kPropagateOneStep:
  1374.                     PropagateCurrentbyOne();
  1375.                     break;
  1376.                 case kReturnToInitial:
  1377.                     ReturnToInitial();                    
  1378.                     break;
  1379.                 case kStartFromCurrent:
  1380.                     StartFromCurrent();
  1381.                     break;
  1382.                 default:
  1383.                     break;
  1384.             }
  1385.             break;
  1386.         case kTestMenu:
  1387.             switch (itemNumber)
  1388.             {
  1389.                 case kTestWhole:
  1390.                 case kTestContinue:
  1391.                     TestWholeFile();
  1392.                     break;
  1393.                 case kDisplayInitial:
  1394.                     gDisplayState = 1;
  1395.                     UpdateLifeWindow();
  1396.                     break;
  1397.                 case kDisplayPrevious:
  1398.                     if (gPreviousState.portBits.baseAddr != nil)
  1399.                     {
  1400.                         gDisplayState = 3;
  1401.                         UpdateLifeWindow();
  1402.                     }
  1403.                     break;
  1404.                 case kDisplayCurrent:
  1405.                     if (gCurrentState.portBits.baseAddr != nil)
  1406.                     {
  1407.                         gDisplayState = 2;
  1408.                         UpdateLifeWindow();
  1409.                     }
  1410.                     break;
  1411.                 case kDisplayGood:
  1412.                     if (gTempFinalState.portBits.baseAddr != nil)
  1413.                     {
  1414.                     gDisplayState = 4;
  1415.                     UpdateLifeWindow();
  1416.                     }
  1417.                     break;
  1418.                 case kDisplayErrors:
  1419.                     if (gErrorState.portBits.baseAddr != nil)
  1420.                     {
  1421.                     gDisplayState = 5;
  1422.                     UpdateLifeWindow();
  1423.                     }
  1424.                     break;
  1425.                 default:
  1426.                     break;
  1427.             }
  1428.         default    :
  1429.             break;
  1430.     }
  1431.     HiliteMenu(0);
  1432.     
  1433. }
  1434.  
  1435. void DoKey(EventRecord *event)
  1436. {    char    c;
  1437.     
  1438.     c = (char)event->message & charCodeMask;
  1439.  
  1440.     if((event->modifiers & cmdKey) == false)
  1441.     {
  1442.     }    else 
  1443.     {
  1444.         PrepareMenus();
  1445.         DoMenu(MenuKey(c));    
  1446.     }
  1447. }
  1448.  
  1449. void DoMouseDown(EventRecord *event)
  1450. {
  1451.     WindowPtr    theWindow;
  1452.     Point            clickP;
  1453.     Rect            cellRect;
  1454.     RgnHandle    cellRgn;
  1455.     short            ratio;
  1456.     EventRecord    mouseEv;
  1457.     GrafPtr        savePort;
  1458.     
  1459.     switch (FindWindow(event->where, &theWindow))
  1460.     {
  1461.         case inDesk:
  1462.             break;    //out of the application
  1463.         case inMenuBar:
  1464.             PrepareMenus();
  1465.             DoMenu(MenuSelect(event->where));
  1466.             break;
  1467.         case inContent:
  1468.             if ((theWindow == gLifeW) && (gDisplayState == 1))
  1469.             {
  1470.                 GetPort(&savePort);
  1471.                 SetPort(gLifeW);
  1472.                 cellRgn = NewRgn();
  1473.                 clickP = event->where;
  1474.                 GlobalToLocal(&clickP);
  1475.                 ClickSet(&gInitialState, gLifeW, &gDisplayRect, &clickP, &ratio);
  1476.                 LocalToGlobal(&clickP);
  1477.                 while (Button())
  1478.                 {
  1479.                     SetRect(&cellRect, clickP.h -1, clickP.v -1,
  1480.                                 clickP.h + ratio, clickP.v + ratio);
  1481.                     RectRgn(cellRgn, &cellRect);
  1482.                     if (WaitNextEvent(osMask, &mouseEv, 10, cellRgn))
  1483.                     {
  1484.                     clickP = mouseEv.where;
  1485.                     GlobalToLocal(&clickP);
  1486.                     ClickSet(&gInitialState, gLifeW, &gDisplayRect, 
  1487.                                 &clickP, &ratio);
  1488.                     LocalToGlobal(&clickP);
  1489.                     }
  1490.                 }
  1491.                 DisposeRgn(cellRgn);
  1492.                 SetPort(savePort);
  1493.                 gInitialSaved = gCurrentSaved = false;
  1494.                 if (gInTest)
  1495.                 {
  1496.                     sprintf((char*)gMessage1, (char*)"\p");
  1497.                     sprintf((char*)gMessage2, (char*)"\p");
  1498.                     gInTest = false;
  1499.                 }
  1500.             }
  1501.             break;
  1502.         case inSysWindow:
  1503.             SystemClick(event,theWindow);
  1504.             break;
  1505.         default:
  1506.             break;
  1507.     }
  1508. }
  1509.  
  1510. void main (void)
  1511. {
  1512.     EventRecord        theEvent;
  1513.  
  1514.     InitAll();
  1515. #ifdef _profile_
  1516.     if (!ProfilerInit(collectDetailed, bestTimeBase, 30, 20))
  1517.     {
  1518. #endif
  1519.     while (!gQuit)
  1520.     {
  1521.         if (WaitNextEvent(everyEvent, &theEvent, 10, nil))
  1522.         {
  1523.             switch (theEvent.what)
  1524.             {
  1525.                 case mouseDown:    
  1526.                     DoMouseDown(&theEvent);
  1527.                     break;                    
  1528.                 case keyDown: case autoKey:
  1529.                     DoKey(&theEvent);
  1530.                     break;
  1531.                 case updateEvt:
  1532.                     BeginUpdate((WindowPtr)theEvent.message);
  1533.                     if ((WindowPtr)theEvent.message == gLifeW)
  1534.                     {    
  1535.                         UpdateLifeWindow();
  1536.                     }
  1537.                     EndUpdate((WindowPtr)theEvent.message);
  1538.                     break;
  1539.                 case osEvt:
  1540.                     theEvent.when++;
  1541.                     break;
  1542.                 default:
  1543.                     break;
  1544.             }
  1545.         }
  1546.     }
  1547. #ifdef _profile_
  1548.     ProfilerDump("\pLifeDump");
  1549.     ProfilerTerm();
  1550.     
  1551.     } else
  1552.         SysBeep(5);
  1553. #endif
  1554. }
  1555.